package com.ht.dsp;

import com.ht.aems.fesmodel.data.MeasurePoint;
import rtdb.pas.SeFesPoints;

import java.util.Calendar;
import java.util.Date;

/**
 * Created by IntelliJ IDEA.
 * User: Dong Shufeng
 * Date: 11-8-26
 */
public class SePointsFiller {

    public static void updateSePoints(SeFesPoints sePoints, long endTime, long elapseTime, int pointNum, double eligibleR, boolean converged) {
        if (sePoints.dayCount == null) ;
        else if (setMeasureTime(endTime, sePoints.dayCount))
            sePoints.dayCount.setEngValue(1);
        else
            sePoints.dayCount.setEngValue(sePoints.dayCount.getEngValue() + 1);

        if (sePoints.monthCount == null) ;
        else if (setMeasureTime(endTime, sePoints.monthCount))
            sePoints.monthCount.setEngValue(1);
        else
            sePoints.monthCount.setEngValue(sePoints.monthCount.getEngValue() + 1);

        if (sePoints.yearCount == null) ;
        else if (setMeasureTime(endTime, sePoints.yearCount))
            sePoints.yearCount.setEngValue(1);
        else
            sePoints.yearCount.setEngValue(sePoints.yearCount.getEngValue() + 1);

        if (sePoints.dayConvergeRate == null || sePoints.dayCount == null) ;
        else if (setMeasureTime(endTime, sePoints.dayConvergeRate))
            sePoints.dayConvergeRate.setEngValue(converged ? 1.0 : 0.0);
        else
            sePoints.dayConvergeRate.setEngValue(((converged ? 1.0 : 0.0) + sePoints.dayConvergeRate.getEngValue() * sePoints.dayCount.getEngValue()) / (1.0 + sePoints.dayCount.getEngValue()));

        if (sePoints.monthConvergeRate == null || sePoints.monthCount == null) ;
        else if (setMeasureTime(endTime, sePoints.monthConvergeRate))
            sePoints.monthConvergeRate.setEngValue(converged ? 1.0 : 0.0);
        else
            sePoints.monthConvergeRate.setEngValue(((converged ? 1.0 : 0.0) + sePoints.monthConvergeRate.getEngValue() * sePoints.monthCount.getEngValue()) / (1.0 + sePoints.monthCount.getEngValue()));

        if (sePoints.yearConvergeRate == null || sePoints.yearCount == null) ;
        else if (setMeasureTime(endTime, sePoints.yearConvergeRate))
            sePoints.yearConvergeRate.setEngValue(converged ? 1.0 : 0.0);
        else
            sePoints.yearConvergeRate.setEngValue(((converged ? 1.0 : 0.0) + sePoints.yearConvergeRate.getEngValue() * sePoints.yearCount.getEngValue()) / (1.0 + sePoints.yearCount.getEngValue()));

        if (sePoints.dayAvailableRate != null && sePoints.dayConvergeRate != null) {
            sePoints.dayAvailableRate.setTimestamp(new Date(endTime));
            sePoints.dayAvailableRate.setEngValue(sePoints.dayConvergeRate.getEngValue());
        }
        if (sePoints.monthAvailableRate != null && sePoints.monthConvergeRate != null) {
            sePoints.monthAvailableRate.setTimestamp(new Date(endTime));
            sePoints.monthAvailableRate.setEngValue(sePoints.monthConvergeRate.getEngValue());
        }
        if (sePoints.yearAvailableRate != null && sePoints.yearConvergeRate != null) {
            sePoints.yearAvailableRate.setTimestamp(new Date(endTime));
            sePoints.yearAvailableRate.setEngValue(sePoints.yearConvergeRate.getEngValue());
        }
        //current
        if (sePoints.analogNum != null) {
            sePoints.analogNum.setTimestamp(new Date(endTime));
            sePoints.analogNum.setEngValue(pointNum);
        }
        if (sePoints.coverRate != null) {
            sePoints.coverRate.setTimestamp(new Date(endTime));
            sePoints.coverRate.setEngValue(100.0);//todo: wrong
        }
        if (sePoints.elapsedTime != null) {
            sePoints.elapsedTime.setTimestamp(new Date(endTime));
            sePoints.elapsedTime.setEngValue(elapseTime);
        }

        if (!converged)
            return;
        if (sePoints.eligibleRate != null)
            sePoints.eligibleRate.setEngValue(eligibleR);
        if (sePoints.dayMaxEligibleRate == null) ;
        else if (setMeasureTime(endTime, sePoints.dayMaxEligibleRate))
            sePoints.dayMaxEligibleRate.setEngValue(eligibleR);
        else
            sePoints.dayMaxEligibleRate.setEngValue(eligibleR > sePoints.dayMaxEligibleRate.getEngValue() ? eligibleR : sePoints.dayMaxEligibleRate.getEngValue());

        if (sePoints.dayMinEligibleRate == null) ;
        else if (setMeasureTime(endTime, sePoints.dayMinEligibleRate))
            sePoints.dayMinEligibleRate.setEngValue(eligibleR);
        else
            sePoints.dayMinEligibleRate.setEngValue(eligibleR < sePoints.dayMinEligibleRate.getEngValue() || sePoints.dayMinEligibleRate.getEngValue() == -999 ? eligibleR : sePoints.dayMinEligibleRate.getEngValue());

        if (sePoints.dayAverageEligibleRate == null || sePoints.dayCount == null) ;
        else if (setMeasureTime(endTime, sePoints.dayAverageEligibleRate))
            sePoints.dayAverageEligibleRate.setEngValue(eligibleR);
        else
            sePoints.dayAverageEligibleRate.setEngValue((eligibleR + sePoints.dayAverageEligibleRate.getEngValue() * sePoints.dayCount.getEngValue()) / (1.0 + sePoints.dayCount.getEngValue()));

        if (sePoints.monthMaxEligibleRate == null) ;
        else if (setMeasureTime(endTime, sePoints.monthMaxEligibleRate))
            sePoints.monthMaxEligibleRate.setEngValue(eligibleR);
        else
            sePoints.monthMaxEligibleRate.setEngValue(eligibleR > sePoints.monthMaxEligibleRate.getEngValue() ? eligibleR : sePoints.monthMaxEligibleRate.getEngValue());


        if (sePoints.monthMinEligibleRate == null) ;
        else if (setMeasureTime(endTime, sePoints.monthMinEligibleRate))
            sePoints.monthMinEligibleRate.setEngValue(eligibleR);
        else
            sePoints.monthMinEligibleRate.setEngValue(eligibleR < sePoints.monthMinEligibleRate.getEngValue() || sePoints.monthMinEligibleRate.getEngValue() == -999 ? eligibleR : sePoints.monthMinEligibleRate.getEngValue());

        if (sePoints.monthAverageEligibleRate == null || sePoints.monthCount == null) ;
        else if (setMeasureTime(endTime, sePoints.monthAverageEligibleRate))
            sePoints.monthAverageEligibleRate.setEngValue(eligibleR);
        else
            sePoints.monthAverageEligibleRate.setEngValue((eligibleR + sePoints.monthAverageEligibleRate.getEngValue() * sePoints.monthCount.getEngValue()) / (1.0 + sePoints.monthCount.getEngValue()));

        if (sePoints.yearMaxEligibleRate == null) ;
        else if (setMeasureTime(endTime, sePoints.yearMaxEligibleRate))
            sePoints.yearMaxEligibleRate.setEngValue(eligibleR);
        else
            sePoints.yearMaxEligibleRate.setEngValue(eligibleR > sePoints.yearMaxEligibleRate.getEngValue() ? eligibleR : sePoints.yearMaxEligibleRate.getEngValue());

        if (sePoints.yearMinEligibleRate == null) ;
        else if (setMeasureTime(endTime, sePoints.yearMinEligibleRate))
            sePoints.yearMinEligibleRate.setEngValue(eligibleR);
        else
            sePoints.yearMinEligibleRate.setEngValue(eligibleR < sePoints.yearMinEligibleRate.getEngValue() || sePoints.yearMinEligibleRate.getEngValue() == -999 ? eligibleR : sePoints.yearMinEligibleRate.getEngValue());

        if (sePoints.yearAverageEligibleRate == null || sePoints.yearCount == null) ;
        else if (setMeasureTime(endTime, sePoints.yearAverageEligibleRate))
            sePoints.yearAverageEligibleRate.setEngValue(eligibleR);
        else
            sePoints.yearAverageEligibleRate.setEngValue((eligibleR + sePoints.yearAverageEligibleRate.getEngValue() * sePoints.yearCount.getEngValue()) / (1.0 + sePoints.yearCount.getEngValue()));
    }

    /**
     * @param seTime end time state estimation
     * @param p      the measurement point to be set
     * @return if the value of the measurement should be reset
     */
    private static boolean setMeasureTime(long seTime, MeasurePoint p) {
        if (p.getTimestamp() == null) {
            p.setTimestamp(new Date(seTime));
            return true;
        }
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(seTime);
        Calendar pointTime = Calendar.getInstance();
        pointTime.setTime(p.getTimestamp());
        int rtType = p.getMeasureType();
        boolean result = false;
        switch (rtType) {
            case MeasurePoint.DAY:
                if (pointTime.get(Calendar.YEAR) != c.get(Calendar.YEAR) ||
                        pointTime.get(Calendar.DAY_OF_YEAR) != c.get(Calendar.DAY_OF_YEAR))
                    result = true;
            case MeasurePoint.MONTH:
                if (pointTime.get(Calendar.YEAR) != c.get(Calendar.YEAR) ||
                        pointTime.get(Calendar.MONTH) != c.get(Calendar.MONTH))
                    result = true;
            case MeasurePoint.YEAR:
                if (pointTime.get(Calendar.YEAR) != c.get(Calendar.YEAR))
                    result = true;
            default:
                break;
        }
        p.setTimestamp(new Date(seTime));
        return result;
    }
}
